/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>

#include <algorithm>
#include <array>
#include <cstdint>
#include <functional>
#include <string>
#include <vector>

#include "../../../libraries/ncsi/ncsi_protocol.h"
#include "../../../libraries/ncsi/ncsi_wx.h"
#include "../../../libraries/ncsi_over_mctp/ncsi_over_mctp_wx.h"

namespace mc {
class dict;
}

namespace dev {
bool        check_response_data(mc::dict ctx, oem_wx_common_rsp_t* rsp, uint8_t command_id);
mc::dict    get_oem_command_ctx_wx(uint8_t channel_id, uint8_t package_id);
void        set_mctp_request_handler(std::function<bool(const mc::dict&, const std::vector<uint8_t>&,
                                                        std::string&)> handler);
} // namespace dev

namespace {

constexpr uint16_t host_to_be16(uint16_t value) {
    return static_cast<uint16_t>(((value & 0x00FFU) << 8U) | ((value & 0xFF00U) >> 8U));
}

TEST(ncsi_over_mctp_wx_utils, get_oem_command_ctx_wx_sets_expected_fields) {
    auto ctx = dev::get_oem_command_ctx_wx(/*channel_id=*/0x05, /*package_id=*/0x07);
    ASSERT_FALSE(ctx.empty());
    EXPECT_EQ(ctx.at("ChannelId").as<int64_t>(), 0x05);
    EXPECT_EQ(ctx.at("PackageId").as<int64_t>(), 0x07);
    EXPECT_EQ(ctx.at("PacketType").as<int64_t>(), OEM_COMMAND);
    EXPECT_EQ(ctx.at("ExpectRspPacketType").as<int64_t>(), OEM_COMMAND_RSP);
}

TEST(ncsi_over_mctp_wx_utils, check_response_data_accepts_valid_payload) {
    auto ctx = dev::get_oem_command_ctx_wx(0x01, 0x02);

    oem_wx_common_rsp_t rsp{};
    rsp.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
    rsp.reason_code     = host_to_be16(0);
    rsp.manufacturer_id = RSP_WX_MANUFACTURE_ID;
    rsp.command_id      = WX_CMD_GET_TEMPERATURE;

    EXPECT_TRUE(dev::check_response_data(ctx, &rsp, WX_CMD_GET_TEMPERATURE));
}

TEST(ncsi_over_mctp_wx_utils, check_response_data_rejects_error_code) {
    auto ctx = dev::get_oem_command_ctx_wx(0x01, 0x02);

    oem_wx_common_rsp_t rsp{};
    constexpr uint16_t  kFailureCode = 0x0001;
    rsp.response_code   = host_to_be16(kFailureCode);
    rsp.reason_code     = host_to_be16(0x1234);
    rsp.manufacturer_id = RSP_WX_MANUFACTURE_ID;
    rsp.command_id      = WX_CMD_GET_TEMPERATURE;

    EXPECT_FALSE(dev::check_response_data(ctx, &rsp, WX_CMD_GET_TEMPERATURE));
}

TEST(ncsi_over_mctp_wx_utils, check_response_data_rejects_wrong_manufacturer) {
    auto ctx = dev::get_oem_command_ctx_wx(0x01, 0x02);

    oem_wx_common_rsp_t rsp{};
    rsp.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
    rsp.reason_code     = host_to_be16(0);
    rsp.manufacturer_id = 0; // 不匹配的厂商ID
    rsp.command_id      = WX_CMD_GET_TEMPERATURE;

    EXPECT_FALSE(dev::check_response_data(ctx, &rsp, WX_CMD_GET_TEMPERATURE));
}

TEST(ncsi_over_mctp_wx_utils, check_response_data_rejects_wrong_command) {
    auto ctx = dev::get_oem_command_ctx_wx(0x01, 0x02);

    oem_wx_common_rsp_t rsp{};
    rsp.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
    rsp.reason_code     = host_to_be16(0);
    rsp.manufacturer_id = RSP_WX_MANUFACTURE_ID;
    rsp.command_id      = WX_CMD_DISABLE_LLDP;

    EXPECT_FALSE(dev::check_response_data(ctx, &rsp, WX_CMD_GET_TEMPERATURE));
}

class ncsi_over_mctp_wx_test : public ::testing::Test {
protected:
    ncsi_over_mctp_wx_test()
        : m_mctp(nullptr, 0, dev::MCTP_MESSAGE_TYPE_NCSI, ""), m_ncsi(m_mctp) {
    }

    void TearDown() override {
        dev::set_mctp_request_handler(nullptr);
    }

    template <typename T>
    static std::string to_binary_string(const T& value) {
        return std::string(reinterpret_cast<const char*>(&value), sizeof(T));
    }

    dev::mctp                m_mctp;
    dev::ncsi_over_mctp_wx   m_ncsi;
};

TEST_F(ncsi_over_mctp_wx_test, get_temperature_success) {
    dev::set_mctp_request_handler([](const mc::dict& ctx, const std::vector<uint8_t>& data,
                                     std::string& rsp) {
        EXPECT_EQ(ctx.at("PacketType").as<int64_t>(), OEM_COMMAND);
        EXPECT_EQ(ctx.at("ExpectRspPacketType").as<int64_t>(), OEM_COMMAND_RSP);
        EXPECT_EQ(data.size(), static_cast<size_t>(WX_COMMON_DATA_SIZE));
        EXPECT_EQ(data[4], WX_OEM_CMD_REV);
        EXPECT_EQ(data[5], WX_CMD_GET_TEMPERATURE);

        oem_wx_temperature_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_TEMPERATURE;
        response.cur_temp                             = 42;

        rsp = to_binary_string(response);
        return true;
    });

    uint16_t temperature = 0;
    EXPECT_TRUE(m_ncsi.get_temperature(0, 0, &temperature));
    EXPECT_EQ(temperature, 42);
}

TEST_F(ncsi_over_mctp_wx_test, get_temperature_null_pointer_returns_false) {
    EXPECT_FALSE(m_ncsi.get_temperature(0, 0, nullptr));
}

TEST_F(ncsi_over_mctp_wx_test, get_temperature_request_failure_returns_false) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&,
                                     std::string&) { return false; });

    uint16_t temperature = 0;
    EXPECT_FALSE(m_ncsi.get_temperature(0, 0, &temperature));
}

TEST_F(ncsi_over_mctp_wx_test, get_temperature_rejects_short_response) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        rsp.assign(4, '\0');
        return true;
    });

    uint16_t temperature = 0;
    EXPECT_FALSE(m_ncsi.get_temperature(0, 0, &temperature));
}

TEST_F(ncsi_over_mctp_wx_test, get_temperature_rejects_short_payload) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        rsp.assign(8, '\0'); // shorter than minimum
        return true;
    });
    uint16_t temperature = 0;
    EXPECT_FALSE(m_ncsi.get_temperature(0, 0, &temperature));
}

TEST_F(ncsi_over_mctp_wx_test, get_temperature_rejects_invalid_payload) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_temperature_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_TEMPERATURE;
        rsp = to_binary_string(response);
        return true;
    });

    uint16_t temperature = 0;
    EXPECT_FALSE(m_ncsi.get_temperature(0, 0, &temperature));
}

TEST_F(ncsi_over_mctp_wx_test, get_mac_address_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>& data,
                                         std::string& rsp) {
        EXPECT_EQ(data[5], WX_CMD_GET_MAC_ADDRESS);
        oem_wx_mac_address_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_MAC_ADDRESS;
        std::array<uint8_t, 6> mac = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB};
        std::copy(mac.begin(), mac.end(), response.mac_addr);
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t mac[6] = {};
    EXPECT_TRUE(m_ncsi.get_mac_address(0, 0, mac, sizeof(mac)));
    EXPECT_EQ(std::vector<uint8_t>(mac, mac + 6), (std::vector<uint8_t>{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}));
}

TEST_F(ncsi_over_mctp_wx_test, get_mac_address_handles_null_pointer) {
    EXPECT_FALSE(m_ncsi.get_mac_address(0, 0, nullptr, 6));
}

TEST_F(ncsi_over_mctp_wx_test, get_mac_address_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    uint8_t mac[6] = {};
    EXPECT_FALSE(m_ncsi.get_mac_address(0, 0, mac, sizeof(mac)));
}

TEST_F(ncsi_over_mctp_wx_test, get_mac_address_rejects_invalid_payload) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_mac_address_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t mac[6] = {};
    EXPECT_FALSE(m_ncsi.get_mac_address(0, 0, mac, sizeof(mac)));
}

TEST_F(ncsi_over_mctp_wx_test, get_serial_number_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>& data, std::string& rsp) {
        EXPECT_EQ(data[5], WX_CMD_GET_SERIAL_NUMBER);
        oem_wx_serial_number_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_SERIAL_NUMBER;
        std::array<uint8_t, WX_SERIAL_NUMBER_MAX_LEN> sn = {0x10, 0x11, 0x12, 0x13, 0x21, 0x22, 0x23, 0x24, 0x25};
        std::copy(sn.begin(), sn.end(), response.serial_number);
        rsp = to_binary_string(response);
        return true;
    });

    std::string serial;
    EXPECT_TRUE(m_ncsi.get_serial_number(0, 0, serial));
    EXPECT_EQ(serial, "252423222113121110");
}

TEST_F(ncsi_over_mctp_wx_test, get_serial_number_invalid_payload_size) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        rsp.assign(8, '\0'); // shorter than expected
        return true;
    });
    std::string serial;
    EXPECT_FALSE(m_ncsi.get_serial_number(0, 0, serial));
}

TEST_F(ncsi_over_mctp_wx_test, get_serial_number_invalid_payload_header) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_serial_number_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = std::string(reinterpret_cast<const char*>(&response), sizeof(response));
        return true;
    });
    std::string serial;
    EXPECT_FALSE(m_ncsi.get_serial_number(0, 0, serial));
}

TEST_F(ncsi_over_mctp_wx_test, get_serial_number_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    std::string serial;
    EXPECT_FALSE(m_ncsi.get_serial_number(0, 0, serial));
}

TEST_F(ncsi_over_mctp_wx_test, enable_lldp_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>& data, std::string& rsp) {
        EXPECT_EQ(data[5], WX_CMD_ENABLE_LLDP);
        oem_wx_get_lldp_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_ENABLE_LLDP;
        rsp = to_binary_string(response);
        return true;
    });

    EXPECT_NO_THROW(m_ncsi.enable_lldp(0, 0));
}

TEST_F(ncsi_over_mctp_wx_test, enable_lldp_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    EXPECT_FALSE(m_ncsi.enable_lldp(0, 0));
}

TEST_F(ncsi_over_mctp_wx_test, enable_lldp_invalid_payload) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_lldp_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = to_binary_string(response);
        return true;
    });

    EXPECT_FALSE(m_ncsi.enable_lldp(0, 0));
}

TEST_F(ncsi_over_mctp_wx_test, disable_lldp_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>& data, std::string& rsp) {
        EXPECT_EQ(data[5], WX_CMD_DISABLE_LLDP);
        oem_wx_get_lldp_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_DISABLE_LLDP;
        rsp = to_binary_string(response);
        return true;
    });

    EXPECT_TRUE(m_ncsi.disable_lldp(0, 0));
}

TEST_F(ncsi_over_mctp_wx_test, disable_lldp_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    EXPECT_FALSE(m_ncsi.disable_lldp(0, 0));
}

TEST_F(ncsi_over_mctp_wx_test, get_lldp_capability_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_lldp_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_LLDP_CAPABILITY;
        response.lldp_capability                      = 0xAA;
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t capability = 0;
    EXPECT_TRUE(m_ncsi.get_lldp_capability(0, 0, &capability));
    EXPECT_EQ(capability, 0xAA);
}

TEST_F(ncsi_over_mctp_wx_test, get_lldp_capability_null_pointer) {
    EXPECT_FALSE(m_ncsi.get_lldp_capability(0, 0, nullptr));
}

TEST_F(ncsi_over_mctp_wx_test, get_lldp_capability_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    uint8_t capability = 0;
    EXPECT_FALSE(m_ncsi.get_lldp_capability(0, 0, &capability));
}

TEST_F(ncsi_over_mctp_wx_test, get_lldp_capability_invalid_payload) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_lldp_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t capability = 0;
    EXPECT_FALSE(m_ncsi.get_lldp_capability(0, 0, &capability));
}

TEST_F(ncsi_over_mctp_wx_test, get_sff_info_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_sff_info_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_SFF_INFO;
        response.temp_high_alarm                      = 0x0102;
        response.temp_high_warning                    = 0x0304;
        response.temp_value                           = 0x0506;
        response.tx_output_pwr                        = 0x0708;
        response.rx_input_pwr                         = 0x090A;
        response.media_type                           = 0x0B;
        rsp = to_binary_string(response);
        return true;
    });

    dev::wx_ncsi_sff_info_t info{};
    EXPECT_TRUE(m_ncsi.get_sff_info(0, 0, &info));
    EXPECT_EQ(info.temp_high_alarm, 0x0102);
    EXPECT_EQ(info.media_type, 0x0B);
}

TEST_F(ncsi_over_mctp_wx_test, get_sff_info_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    dev::wx_ncsi_sff_info_t info{};
    EXPECT_FALSE(m_ncsi.get_sff_info(0, 0, &info));
}

TEST_F(ncsi_over_mctp_wx_test, get_sff_info_invalid_payload) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_sff_info_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = to_binary_string(response);
        return true;
    });

    dev::wx_ncsi_sff_info_t info{};
    EXPECT_FALSE(m_ncsi.get_sff_info(0, 0, &info));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_sn_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_vpd_sn_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_VPD_SN;
        response.sn_len                                = 3;
        response.sn[0]                                 = 0xAA;
        response.sn[1]                                 = 0xBB;
        response.sn[2]                                 = 0xCC;
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t buffer[24] = {};
    uint8_t length     = 0;
    EXPECT_TRUE(m_ncsi.get_vpd_sn(0, 0, buffer, &length));
    EXPECT_EQ(length, 3);
    EXPECT_EQ(std::vector<uint8_t>(buffer, buffer + 3), (std::vector<uint8_t>{0xAA, 0xBB, 0xCC}));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_sn_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    uint8_t buffer[24] = {};
    uint8_t length     = 0;
    EXPECT_FALSE(m_ncsi.get_vpd_sn(0, 0, buffer, &length));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_sn_handles_null_arguments) {
    EXPECT_FALSE(m_ncsi.get_vpd_sn(0, 0, nullptr, nullptr));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_sn_invalid_payload) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_vpd_sn_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = std::string(reinterpret_cast<const char*>(&response), sizeof(response));
        return true;
    });
    uint8_t buffer[24] = {};
    uint8_t length     = 0;
    EXPECT_FALSE(m_ncsi.get_vpd_sn(0, 0, buffer, &length));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_pn_success) {
    dev::set_mctp_request_handler([this](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_vpd_pn_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = RSP_WX_MANUFACTURE_ID;
        response.wx_rsp_common_header.command_id      = WX_CMD_GET_VPD_PN;
        response.pn_len                                = 2;
        response.pn[0]                                 = 0x11;
        response.pn[1]                                 = 0x22;
        rsp = to_binary_string(response);
        return true;
    });

    uint8_t buffer[32] = {};
    uint8_t length     = 0;
    EXPECT_TRUE(m_ncsi.get_vpd_pn(0, 0, buffer, &length));
    EXPECT_EQ(length, 2);
    EXPECT_EQ(std::vector<uint8_t>(buffer, buffer + 2), (std::vector<uint8_t>{0x11, 0x22}));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_pn_request_failure) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });
    uint8_t buffer[32] = {};
    uint8_t length     = 0;
    EXPECT_FALSE(m_ncsi.get_vpd_pn(0, 0, buffer, &length));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_pn_handles_null_arguments) {
    EXPECT_FALSE(m_ncsi.get_vpd_pn(0, 0, nullptr, nullptr));
}

TEST_F(ncsi_over_mctp_wx_test, get_vpd_pn_invalid_payload) {
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string& rsp) {
        oem_wx_get_vpd_pn_rsp_t response{};
        response.wx_rsp_common_header.response_code   = host_to_be16(WX_RESP_CODE_SUCCESS);
        response.wx_rsp_common_header.reason_code     = host_to_be16(WX_REASON_CODE_SUCCESS);
        response.wx_rsp_common_header.manufacturer_id = 0;
        rsp = std::string(reinterpret_cast<const char*>(&response), sizeof(response));
        return true;
    });
    uint8_t buffer[32] = {};
    uint8_t length     = 0;
    EXPECT_FALSE(m_ncsi.get_vpd_pn(0, 0, buffer, &length));
}

} // namespace

